﻿using System;
using System.Collections.Generic;

namespace Accona.Remoting.Interaction
{
    /// <summary>
    /// This class is used for interacting between different parts of a system. Each part exposes a service that inherits from IInteraction.
    /// The service is registered into the InteractionServiceManager for a specific implementation.
    /// </summary>
    public class InteractionServiceManager
    {
        private readonly Dictionary<Type, IRegistredHandler> registeredHandlers =
            new Dictionary<Type, IRegistredHandler>();

        private readonly Dictionary<Type, IInteraction> registeredServices = new Dictionary<Type, IInteraction>();

        /// <summary>
        /// Returns the actual implementation for a specific service
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetService<T>() where T : class, IInteraction
        {
            IInteraction registeredService = registeredServices[typeof (T)];
            if (registeredService != null)
                return (T) registeredService;
            return null;
        }

        public void ProcessInteractionRequest(IInteraction interaction)
        {
            IRegistredHandler value;
            if (registeredHandlers.TryGetValue(interaction.GetType(), out value))
            {
                if (value.InvokePredicate(interaction))
                    value.InvokeAction(interaction);
            }
        }

        public void RegisterService(IInteraction interaction)
        {
            registeredServices.Add(interaction.GetType(), interaction);
        }

        /// <summary>
        /// Checks whether a service is installed or not
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public bool IsInstalled<T>() where T : IInteraction
        {
            return registeredServices.ContainsKey(typeof (T));
        }


        public void RegisterHandler<TInterface>(Predicate<TInterface> predicate, Action<TInterface> action)
            where TInterface : IInteraction
        {
            var handler = new RegisteredHandler<TInterface>
                              {
                                  Action = action,
                                  Predicate = predicate,
                                  Type = typeof (TInterface)
                              };
            registeredHandlers.Add(handler.Type, handler);
        }

        #region Nested type: IRegistredHandler

        internal interface IRegistredHandler
        {
            Type Type { get; set; }
            bool InvokePredicate(IInteraction interaction);
            void InvokeAction(IInteraction interaction);
        }

        #endregion

        #region Nested type: RegisteredHandler

        internal class RegisteredHandler<TInterface> : IRegistredHandler where TInterface : IInteraction
        {
            public Predicate<TInterface> Predicate { get; set; }
            public Action<TInterface> Action { get; set; }

            #region IRegistredHandler Members

            public Type Type { get; set; }

            public bool InvokePredicate(IInteraction interaction)
            {
                return Predicate.Invoke((TInterface) interaction);
            }

            public void InvokeAction(IInteraction interaction)
            {
                Action.Invoke((TInterface) interaction);
            }

            #endregion
        }

        #endregion
    }
}